package scu.maqiang.mesh;

import java.util.Arrays;

import scu.maqiang.numeric.SIMatrix;

public class Mesh3H20 extends Mesh {

	public Mesh3H20() {
		super();
		nDim = 3;
		nPerElement = 20;
		nPerBoundary = 8;
		nBoundaryPerElement = 6;
		nEdgePerElement = 24;
		nEdgePerBoundary = 2;
		tecplotType = "FEBRICK";
	}

	public Mesh3H20(Mesh3H8 mshR) {
		this();
		SIMatrix C = mshR.renumberingEdges();
		int sizeC = C.getNNZ();
		int[] idxI = new int[sizeC];
		int[] idxJ = new int[sizeC];
		int[] value = new int[sizeC];
		int[] number = new int[sizeC];
		C.getTriValues(idxI, idxJ, value);
		Arrays.setAll(number, i -> i);

		nv = sizeC + mshR.nv;
		nodes = new double[nv][];
		nodeLabel = new int[nv];
		int[][] edges = new int[mshR.nt][12];
		for (int i = 0, n = mshR.getNt(); i < n; i++) {
//			int[] tri = mshR.elements[i];
//			double[][] d = {{tri[0], tri[1]}, {tri[1], tri[2]}, {tri[2], tri[3]}, {tri[3], tri[0]},
//					        {tri[4], tri[5]}, {tri[5], tri[6]}, {tri[6], tri[7]}, {tri[7], tri[4]},
//					        {tri[0], tri[4]}, {tri[1], tri[5]}, {tri[2], tri[6]}, {tri[3], tri[7]}};
			int[][] d = mshR.getEdgesFromElement(i);
//			System.out.println(MVO.toString(d));
			for(int k = 0, m = d.length; k < m; k++) {
				for (int j = 0; j < sizeC; j++) {
					if ((idxI[j] == d[k][0] && idxJ[j] == d[k][1]) || (idxI[j] == d[k][1] && idxJ[j] == d[k][0])) {
						edges[i][k] = j + mshR.nv;
						break;
					}
				}
			}
		}

		//System.out.println(MVO.toString(edges));
		for (int i = 0; i < mshR.nv; i++) {
			nodes[i] = mshR.nodes[i].clone();
		}
		for (int i = mshR.nv; i < nv; i++) {
			nodes[i] = new double[nDim];
		}
		nt = mshR.getNt();
		elements = new int[nt][];
		elementLabel = mshR.elementLabel.clone();
		for (int i = 0, n = mshR.getNt(); i < n; i++) {
			int[] hex8 = mshR.elements[i];
			double[][] node = new double[8][];
			for (int j = 0; j < 8; j++) {
				node[j] = mshR.nodes[hex8[j]];
			}
			nodes[edges[i][0]] = new double[] {0.5 * (node[0][0] + node[1][0]), 0.5 * (node[0][1] + node[1][1]), 0.5 * (node[0][2] + node[1][2])};
			nodes[edges[i][1]] = new double[] {0.5 * (node[1][0] + node[2][0]), 0.5 * (node[1][1] + node[2][1]), 0.5 * (node[1][2] + node[2][2])};
			nodes[edges[i][2]] = new double[] {0.5 * (node[2][0] + node[3][0]), 0.5 * (node[2][1] + node[3][1]), 0.5 * (node[2][2] + node[3][2])};
			nodes[edges[i][3]] = new double[] {0.5 * (node[3][0] + node[0][0]), 0.5 * (node[3][1] + node[0][1]), 0.5 * (node[3][2] + node[0][2])};
			nodes[edges[i][4]] = new double[] {0.5 * (node[4][0] + node[5][0]), 0.5 * (node[4][1] + node[5][1]), 0.5 * (node[4][2] + node[5][2])};
			nodes[edges[i][5]] = new double[] {0.5 * (node[5][0] + node[6][0]), 0.5 * (node[5][1] + node[6][1]), 0.5 * (node[5][2] + node[6][2])};
			nodes[edges[i][6]] = new double[] {0.5 * (node[6][0] + node[7][0]), 0.5 * (node[6][1] + node[7][1]), 0.5 * (node[6][2] + node[7][2])};
			nodes[edges[i][7]] = new double[] {0.5 * (node[7][0] + node[4][0]), 0.5 * (node[7][1] + node[4][1]), 0.5 * (node[7][2] + node[4][2])};
			nodes[edges[i][8]] = new double[] {0.5 * (node[0][0] + node[4][0]), 0.5 * (node[0][1] + node[4][1]), 0.5 * (node[0][2] + node[4][2])};
			nodes[edges[i][9]] = new double[] {0.5 * (node[1][0] + node[5][0]), 0.5 * (node[1][1] + node[5][1]), 0.5 * (node[1][2] + node[5][2])};
			nodes[edges[i][10]] = new double[] {0.5 * (node[2][0] + node[6][0]), 0.5 * (node[2][1] + node[6][1]), 0.5 * (node[2][2] + node[6][2])};
			nodes[edges[i][11]] = new double[] {0.5 * (node[3][0] + node[7][0]), 0.5 * (node[3][1] + node[7][1]), 0.5 * (node[3][2] + node[7][2])};
			// ����µ�Ԫ
			elements[i] = new int[] { hex8[0], hex8[1], hex8[2], hex8[3],  hex8[4], hex8[5], hex8[6], hex8[7],
					edges[i][0], edges[i][1], edges[i][2], edges[i][3],
					edges[i][4], edges[i][5], edges[i][6], edges[i][7],
					edges[i][8], edges[i][9], edges[i][10], edges[i][11]};
		}

		nb = mshR.nb;
		int d1, d2;
		int[] edgeNum = new int[4];
		boundaries = new int[nb][];
		boundaryLabel = mshR.boundaryLabel.clone();
		for (int i = 0; i < nb; i++) {
			int[] quad4 = mshR.boundaries[i];
			d1 = quad4[0];
			d2 = quad4[1];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edgeNum[0] = j + mshR.nv;
					break;
				}
			}

			d1 = quad4[1];
			d2 = quad4[2];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edgeNum[1] = j + mshR.nv;
					break;
				}
			}

			d1 = quad4[2];
			d2 = quad4[3];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edgeNum[2] = j + mshR.nv;
					break;
				}
			}

			d1 = quad4[3];
			d2 = quad4[0];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edgeNum[3] = j + mshR.nv;
					break;
				}
			}
			boundaries[i] = new int[] {quad4[0], quad4[1], quad4[2], quad4[3], edgeNum[0], edgeNum[1], edgeNum[2], edgeNum[3]};
		}
	}

	public void fromMesh3DH8(Mesh3H8 mshR) {
		SIMatrix C = mshR.renumberingEdges();
		int sizeC = C.getNNZ();
		int[] idxI = new int[sizeC];
		int[] idxJ = new int[sizeC];
		int[] value = new int[sizeC];
		int[] number = new int[sizeC];
		C.getTriValues(idxI, idxJ, value);
		Arrays.setAll(number, i -> i);

		nv = sizeC + mshR.nv;
		nodes = new double[nv][];
		nodeLabel = new int[nv];
		int[][] edges = new int[mshR.nt][12];
		for (int i = 0, n = mshR.getNt(); i < n; i++) {
//			int[] tri = mshR.elements[i];
//			double[][] d = {{tri[0], tri[1]}, {tri[1], tri[2]}, {tri[2], tri[3]}, {tri[3], tri[0]},
//					        {tri[4], tri[5]}, {tri[5], tri[6]}, {tri[6], tri[7]}, {tri[7], tri[4]},
//					        {tri[0], tri[4]}, {tri[1], tri[5]}, {tri[2], tri[6]}, {tri[3], tri[7]}};
			int[][] d = mshR.getEdgesFromElement(i);
//			System.out.println(MVO.toString(d));
			for(int k = 0, m = d.length; k < m; k++) {
				for (int j = 0; j < sizeC; j++) {
					if ((idxI[j] == d[k][0] && idxJ[j] == d[k][1]) || (idxI[j] == d[k][1] && idxJ[j] == d[k][0])) {
						edges[i][k] = j + mshR.nv;
						break;
					}
				}
			}
		}

		//System.out.println(MVO.toString(edges));
		for (int i = 0; i < mshR.nv; i++) {
			nodes[i] = mshR.nodes[i].clone();
		}
		for (int i = mshR.nv; i < nv; i++) {
			nodes[i] = new double[nDim];
		}

		nt = mshR.getNt();
		elements = new int[nt][];
		elementLabel = mshR.elementLabel.clone();
		for (int i = 0, n = mshR.getNt(); i < n; i++) {
			int[] hex8 = mshR.elements[i];
			double[][] node = new double[8][];
			for (int j = 0; j < 8; j++) {
				node[j] = mshR.nodes[hex8[j]];
			}
			nodes[edges[i][0]] = new double[] {0.5 * (node[0][0] + node[1][0]), 0.5 * (node[0][1] + node[1][1]), 0.5 * (node[0][2] + node[1][2])};
			nodes[edges[i][1]] = new double[] {0.5 * (node[1][0] + node[2][0]), 0.5 * (node[1][1] + node[2][1]), 0.5 * (node[1][2] + node[2][2])};
			nodes[edges[i][2]] = new double[] {0.5 * (node[2][0] + node[3][0]), 0.5 * (node[2][1] + node[3][1]), 0.5 * (node[2][2] + node[3][2])};
			nodes[edges[i][3]] = new double[] {0.5 * (node[3][0] + node[0][0]), 0.5 * (node[3][1] + node[0][1]), 0.5 * (node[3][2] + node[0][2])};
			nodes[edges[i][4]] = new double[] {0.5 * (node[4][0] + node[5][0]), 0.5 * (node[4][1] + node[5][1]), 0.5 * (node[4][2] + node[5][2])};
			nodes[edges[i][5]] = new double[] {0.5 * (node[5][0] + node[6][0]), 0.5 * (node[5][1] + node[6][1]), 0.5 * (node[5][2] + node[6][2])};
			nodes[edges[i][6]] = new double[] {0.5 * (node[6][0] + node[7][0]), 0.5 * (node[6][1] + node[7][1]), 0.5 * (node[6][2] + node[7][2])};
			nodes[edges[i][7]] = new double[] {0.5 * (node[7][0] + node[4][0]), 0.5 * (node[7][1] + node[4][1]), 0.5 * (node[7][2] + node[4][2])};
			nodes[edges[i][8]] = new double[] {0.5 * (node[0][0] + node[4][0]), 0.5 * (node[0][1] + node[4][1]), 0.5 * (node[0][2] + node[4][2])};
			nodes[edges[i][9]] = new double[] {0.5 * (node[1][0] + node[5][0]), 0.5 * (node[1][1] + node[5][1]), 0.5 * (node[1][2] + node[5][2])};
			nodes[edges[i][10]] = new double[] {0.5 * (node[2][0] + node[6][0]), 0.5 * (node[2][1] + node[6][1]), 0.5 * (node[2][2] + node[6][2])};
			nodes[edges[i][11]] = new double[] {0.5 * (node[3][0] + node[7][0]), 0.5 * (node[3][1] + node[7][1]), 0.5 * (node[3][2] + node[7][2])};
			// ����µ�Ԫ
			elements[i] = new int[] { hex8[0], hex8[1], hex8[2], hex8[3],  hex8[4], hex8[5], hex8[6], hex8[7],
					edges[i][0], edges[i][1], edges[i][2], edges[i][3],
					edges[i][4], edges[i][5], edges[i][6], edges[i][7],
					edges[i][8], edges[i][9], edges[i][10], edges[i][11]};
		}

		nb = mshR.nb;
		int d1, d2;
		int[] edgeNum = new int[4];
		boundaries = new int[nb][];
		boundaryLabel = mshR.boundaryLabel.clone();
		for (int i = 0; i < nb; i++) {
			int[] quad4 = mshR.boundaries[i];
			d1 = quad4[0];
			d2 = quad4[1];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edgeNum[0] = j + mshR.nv;
					break;
				}
			}

			d1 = quad4[1];
			d2 = quad4[2];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edgeNum[1] = j + mshR.nv;
					break;
				}
			}

			d1 = quad4[2];
			d2 = quad4[3];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edgeNum[2] = j + mshR.nv;
					break;
				}
			}

			d1 = quad4[3];
			d2 = quad4[0];
			for (int j = 0; j < sizeC; j++) {
				if ((idxI[j] == d1 && idxJ[j] == d2) || (idxI[j] == d2 && idxJ[j] == d1)) {
					edgeNum[3] = j + mshR.nv;
					break;
				}
			}
			boundaries[i] = new int[] {quad4[0], quad4[1], quad4[2], quad4[3], edgeNum[0], edgeNum[1], edgeNum[2], edgeNum[3]};
		}
	}
	
	@Override
	public double[] getinteriorPointInElement(double[][] coord) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public double[] getinteriorPointOnBoundary(double[][] coord) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public int[][] getBoundarysFromElement(int i) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public boolean checkMesh(double[][] coord) {
		// TODO Auto-generated method stub
		return false;
	}

	@Override
	public int getTecplotNt() {
		// TODO Auto-generated method stub
		return nt;
	}

	@Override
	public int[][] getEdgesFromElement(int i) {
		int[] element = elements[i];
		int[][] result = new int[24][];
		return null;
	}

}
